using System;
using System.Linq;
using DNT.RavenQA.Core.Extensions;
using DNT.RavenQA.Core.Models;
using Raven.Client;

namespace DNT.RavenQA.Web.Infrastructure.Commands
{
    public abstract class VoteCommand : RavenCommand<VoteCommand.Input, CommandResult<VoteCommand.Result>>
    {
        public struct Input
        {
            public Int32 ContributeId;
            public User User;
        }

        public struct Result
        {
            public Int32 TotalAmount;
            public Type ContributeType;
        }

        protected VoteCommand(Input parameter)
            : base(parameter)
        {
        }

        protected CommandResult<Result> Execute(IDocumentSession session,
                                                Action<Contribute, Func<ContributeVotes>, User> action)
        {
            session.EnsureIsNotNull("session");

            var contribute = GetContribute(session);
            var votes = session.Query<ContributeVotes>()
                           .SingleOrDefault(x => x.ContributeId == contribute.Id);

            Func<ContributeVotes> func = () =>
                                             {
                                                 if (votes.IsNull())
                                                 {
                                                     votes = ContributeVotes.New(contribute);
                                                     session.Store(votes);
                                                 }

                                                 return votes;
                                             };

            action(contribute, func, Parameter.User);
            return new CommandResult<Result>(new Result
                                                 {
                                                     TotalAmount = votes.IsNull() ? 0 : votes.TotalAmount,
                                                     ContributeType = contribute.GetType()
                                                 });
        }

        protected abstract Contribute GetContribute(IDocumentSession session);
    }
}